#pragma once 
#include <string>
#include <vector>
#include <mysql/mysql.h>
#include <iostream>
#include <ctime>
#include <cstdio>
#include <pthread.h>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
#include <fstream>

//日志
#define INF 0
#define DBG 1
#define ERR 2
#define LOG_LEVEL DBG
#define LOG(log_level,format,...)do{\
        if(log_level<LOG_LEVEL)break;\
        time_t t=time(nullptr);\
        struct tm*ltm=localtime(&t);\
        char time_tmp[32]={0};\
        strftime(time_tmp,31,"%Y:%m:%d:%H:%M:%S",ltm);\
        fprintf(stdout,"[%p %s %s:%d]" format "\n",(void*)pthread_self(),\
        time_tmp,__FILE__,__LINE__,##__VA_ARGS__);\
} while (0)

#define INF_LOG(format,...) LOG(INF,format,##__VA_ARGS__)
#define DBG_LOG(format,...) LOG(DBG,format,##__VA_ARGS__)
#define ERR_LOG(format,...) LOG(ERR,format,##__VA_ARGS__)

class file_util
{
public:
   //打开文件filename，把读到的内容放到body中
    static bool read(const std::string &filename, std::string &body)
    {
       std::ifstream file;//创建文件流对象

       file.open(filename.c_str(),std::ios::in|std::ios::binary);//只读+二进制
       if(!file){
        std::cout<<filename<<"Open failed!"<<std::endl;
        return false;
       }

       //打开文件成功
       file.seekg(0,std::ios::end);//读指针设到文件末尾
       body.resize(file.tellg());//获取读指针位置，更新body大小
       file.seekg(0,std::ios::beg);//读指针设到文件开头
       file.read(&body[0],body.size());//读取文件写入缓冲区
       if(file.good()==false){
        std::cout<<filename<<"Read failed!"<<std::endl;
        body.clear();
        file.close();
        return false;
       }
       file.close();
       return true;
      
    }
};

// 封装string工具类
class string_util
{
public:
  // 分隔字符串，分隔符为sep，把分隔的结果放到vector中
  // aa  nn  oo  nn  cc,分隔符为两个空格
  static int split(const std::string &in, const std::string &sep,
                   std::vector<std::string> &array)
  {
    array.clear();
    size_t pos, idx = 0;
    while (idx < in.size())
    {
      pos = in.find(sep, idx);
      if (pos == std::string::npos)
      {
        array.push_back(in.substr(idx));
        break;
      }
      if (pos != idx)
      {
        array.push_back(in.substr(idx, pos - idx)); // 从idx开始切到pos这个位置
      }
      idx = pos + sep.size(); // 更新下一次idx的位置
    }
    return array.size();
  }
};

//封装mysql工具类
class mysql_util
{
public:
    // 创建句柄连接客户端
    static MYSQL *mysql_create(const std::string &host,
                               const std::string &user,
                               const std::string &passwd,
                               const std::string &db_name,
                               uint16_t port)
    {
        // 创建句柄
        MYSQL *mysql = mysql_init(nullptr);
        if (mysql == nullptr)
        {
            std::cout << "mysql_init failed!" << std::endl;
            return nullptr;
        }

        // 连接服务端
        if (mysql_real_connect(mysql, host.c_str(), user.c_str(),
                               passwd.c_str(), db_name.c_str(), port, nullptr, 0) == nullptr)
        {
            std::cout << "mysql_real_connect failed!" << std::endl;
            std::cout << mysql_error(mysql) << std::endl;
            return nullptr;
        }

        // 设置字符集为utf-8
        mysql_set_character_set(mysql, "utf8");
        return mysql;
    }

    // 释放句柄/资源
    static void mysql_destroy(MYSQL *mysql)
    {
        if (mysql != nullptr)
            mysql_close(mysql);
        return;
    }

    // 执行sql语句
    static bool mysql_exec(MYSQL *mysql, const std::string &sql)
    {
        int ret = mysql_query(mysql, sql.c_str());
        if (ret != 0)
        {
            std::cout << sql << " failed!" << std::endl;
            std::cout << mysql_error(mysql) << std::endl;
            return false;
        }
        return true;
    }
};

//封装一个json的序列化和反序列化工具类
class json_util
{
    public:
    //序列化
    static bool serialize(const Json::Value&root ,std::string &str)
    {
      //配置信息
      Json::StreamWriterBuilder swb;
      //实例化对象，并且RAII
      std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
      
      std::stringstream ss;
      int ret=sw->write(root,&ss);//序列化后的结果放到ss中
      if(ret!=0)
      {
        std::cout<<"serialize failed!"<<std::endl;
        return false;//序列化失败
      }
      //序列化成功
      str=ss.str();//把序列化的结果放到str中传出去
      return true;
    }

    //反序列化
    static bool unserialize(const std::string&str,Json::Value&root)
    {
      Json::CharReaderBuilder crb;//反序列化的解析格式
      std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
      if(!cr->parse(str.c_str(),str.c_str()+str.size(),&root,nullptr))
      {
        std::cout<<"unserialize failed!"<<std::endl;
        return false;
      }
      return true;
    }

};